package com.yourenbang.lingyun.transaction.util.lakala.replace;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.*;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

/** 
* @Description: Https辅助类
* 
* 1、如执行serverTrustedHttpsPost（忽略对服务器端证书的校验进行访问-Apache HTTP 组件方式），给客户端提供client.p12
* 
* 2、如执行keystoreHttpsPost（将服务器证书导入keystore cacerts进行访问-Apache HTTP 组件方式），给客户端提供client.p12，server.crt
*    为客户端的JVM导入证书，复制server.crt到security目录下执行（注意需要管理员权限到你使用的JDK security目录下执行）
*    keytool -import -alias *.lakala.com -keystore cacerts -file server.crt
*    密码：changeit
*             
* 3、如执行truststoreHttpsPost（生成truststore库文件进行访问-Apache HTTP 组件方式），给客户端提供client.p12，server.crt
* 	  把server.crt复制一份，重命名为server.cer，复制到security目录下，执行
*    keytool -keystore test.truststore -keypass 123456 -storepass 123456 -alias *.lakala.com -import -trustcacerts -file server.cer
*    生成自己的truststore，就是HttpsUtil里使用的TRUST_STRORE_FILE；
*    
* @date 2017年11月23日
* @author tongxs 
*/
public class HttpsUtil {

	// 客户端证书路径，用了本地绝对路径，需要修改
	private final static String CLIENT_CERT_FILE = "/cert/lakalareplace/client.p12";
	// 客户端证书密码
	private final static String CLIENT_PWD = "123456";
	// 信任库路径
	private final static String TRUST_STRORE_FILE = "D:/workspaces/docManage/Test/cert/test.truststore";
	// 信任库密码
	private final static String TRUST_STORE_PWD = "123456";
	// 信任IP地址，目前这个仅限于测试用，生产时用域名访问，将MyHostnameVerifier方法信任Ip那段逻辑去掉
	private final static String TRUST_IP = "123.124.162.33";

	/**
	 * @Description: 忽略对服务器端证书的校验进行访问-Apache HTTP 组件方式
	 * @param url
	 * @return
	 * @throws Exception
	 * @date 2017年11月23日
	 * @author tongxs
	 */
	public static String serverTrustedHttpsGet(String url) throws Exception {
		String ret = "";
		KeyStore keyStore = getKeyStore(CLIENT_CERT_FILE, CLIENT_PWD, "PKCS12");
		SSLContext sslContext = SSLContexts.custom()
				// 忽略掉对服务器端证书的校验
				.loadTrustMaterial(new TrustStrategy() {
					@Override
					public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
						return true;
					}
				}).loadKeyMaterial(keyStore, CLIENT_PWD.toCharArray()).build();
		SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, new String[] { "TLSv1" }, null,
				new MyHostnameVerifier());

		CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
		try {
			HttpGet httpget = new HttpGet(url);
			CloseableHttpResponse response = httpclient.execute(httpget);
			try {
				HttpEntity entity = response.getEntity();
				// 返回结果
				ret = EntityUtils.toString(response.getEntity(), "UTF-8");
				EntityUtils.consume(entity);
			} finally {
				response.close();
			}
		} finally {
			httpclient.close();
		}
		return ret;
	}

	/**
	 * @Description: 忽略对服务器端证书的校验进行访问-Apache HTTP 组件方式
	 * @param url
	 * @param requestJson
	 * @return
	 * @throws Exception
	 * @date 2017年11月23日
	 * @author tongxs
	 */
	public static String serverTrustedHttpsPost(String url, String requestJson) throws Exception {
		String ret = "";
		KeyStore keyStore = getKeyStore(CLIENT_CERT_FILE, CLIENT_PWD, "PKCS12");
		SSLContext sslContext = SSLContexts.custom()
				// 忽略掉对服务器端证书的校验
				.loadTrustMaterial(new TrustStrategy() {
					@Override
					public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
						return true;
					}
				}).loadKeyMaterial(keyStore, CLIENT_PWD.toCharArray()).build();
		SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, new String[] { "TLSv1" }, null,
				new MyHostnameVerifier());
		CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
		try {
			StringEntity reqEntity = new StringEntity(requestJson, "UTF-8");
			HttpPost httpPost = new HttpPost(url);
			httpPost.setEntity(reqEntity);
			CloseableHttpResponse response = httpclient.execute(httpPost);
			try {
				HttpEntity entity = response.getEntity();
				// 返回结果
				ret = EntityUtils.toString(response.getEntity(), "UTF-8");
				EntityUtils.consume(entity);
			} finally {
				response.close();
			}
		}catch(Exception e){
			e.printStackTrace();
		} finally {
			httpclient.close();
		}
		return ret;
	}

	/**
	 * @Description: 生成truststore库文件进行访问-Apache HTTP 组件方式
	 * @param url
	 * @return
	 * @throws Exception
	 * @date 2017年11月23日
	 * @author tongxs
	 */
	public static String truststoreHttpsGet(String url) throws Exception {
		String ret = "";
		// 初始化密钥库
		KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
		KeyStore keyStore = getKeyStore(CLIENT_CERT_FILE, CLIENT_PWD, "PKCS12");
		keyManagerFactory.init(keyStore, CLIENT_PWD.toCharArray());

		// 初始化信任库
		TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509");
		KeyStore trustkeyStore = getKeyStore(TRUST_STRORE_FILE, TRUST_STORE_PWD, "JKS");
		trustManagerFactory.init(trustkeyStore);

		SSLContext sslContext = SSLContext.getInstance("SSL");
		sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());

		SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, new String[] { "TLSv1" }, null,
				new MyHostnameVerifier());

		CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
		try {
			HttpGet httpget = new HttpGet(url);
			CloseableHttpResponse response = httpclient.execute(httpget);
			try {
				HttpEntity entity = response.getEntity();
				// 返回结果
				ret = EntityUtils.toString(response.getEntity(), "UTF-8");
				EntityUtils.consume(entity);
			} finally {
				response.close();
			}
		} finally {
			httpclient.close();
		}
		return ret;
	}

	/**
	 * @Description: 生成truststore库文件进行访问-Apache HTTP 组件方式
	 * @param url
	 * @param requestJson
	 * @return
	 * @throws Exception
	 * @date 2017年11月23日
	 * @author tongxs
	 */
	public static String truststoreHttpsPost(String url, String requestJson) throws Exception {
		String ret = "";
		// 初始化密钥库
		KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
		KeyStore keyStore = getKeyStore(CLIENT_CERT_FILE, CLIENT_PWD, "PKCS12");
		keyManagerFactory.init(keyStore, CLIENT_PWD.toCharArray());

		// 初始化信任库
		TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509");
		KeyStore trustkeyStore = getKeyStore(TRUST_STRORE_FILE, TRUST_STORE_PWD, "JKS");
		trustManagerFactory.init(trustkeyStore);

		SSLContext sslContext = SSLContext.getInstance("SSL");
		sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());

		SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, new String[] { "TLSv1" }, null,
				new MyHostnameVerifier());

		CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
		try {
			StringEntity reqEntity = new StringEntity(requestJson, "UTF-8");
			HttpPost httpPost = new HttpPost(url);
			httpPost.setEntity(reqEntity);
			CloseableHttpResponse response = httpclient.execute(httpPost);
			try {
				HttpEntity entity = response.getEntity();
				// 返回结果
				ret = EntityUtils.toString(response.getEntity(), "UTF-8");
				EntityUtils.consume(entity);
			} finally {
				response.close();
			}
		} finally {
			httpclient.close();
		}
		return ret;
	}

	/**
	 * @Description: 将服务器证书导入keystore cacerts进行访问-Apache HTTP 组件方式
	 * @param url
	 * @return
	 * @throws Exception
	 * @date 2017年11月23日
	 * @author tongxs
	 */
	public static String keystoreHttpsGet(String url) throws Exception {
		String ret = "";
		KeyStore keyStore = getKeyStore(CLIENT_CERT_FILE, CLIENT_PWD, "PKCS12");

		SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, CLIENT_PWD.toCharArray()).build();
		SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,
				new MyHostnameVerifier());

		CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
		try {
			HttpGet httpget = new HttpGet(url);
			CloseableHttpResponse response = httpclient.execute(httpget);
			try {
				HttpEntity entity = response.getEntity();
				// 返回结果
				ret = EntityUtils.toString(response.getEntity(), "UTF-8");
				EntityUtils.consume(entity);
			} finally {
				response.close();
			}
		} finally {
			httpclient.close();
		}
		return ret;
	}

	/**
	 * @Description: 将服务器证书导入keystore cacerts进行访问-Apache HTTP 组件方式
	 * @param url
	 * @param requestJson
	 * @return
	 * @throws Exception
	 * @date 2017年11月23日
	 * @author tongxs
	 */
	public static String keystoreHttpsPost(String url, String requestJson) throws Exception {

		String ret = "";
		KeyStore keyStore = getKeyStore(CLIENT_CERT_FILE, CLIENT_PWD, "PKCS12");
		SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, CLIENT_PWD.toCharArray()).build();
		SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,
				new MyHostnameVerifier());
		CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
		try {
			StringEntity reqEntity = new StringEntity(requestJson, "UTF-8");
			HttpPost httpPost = new HttpPost(url);
			httpPost.setEntity(reqEntity);
			CloseableHttpResponse response = httpclient.execute(httpPost);
			try {
				HttpEntity entity = response.getEntity();
				// 返回结果
				ret = EntityUtils.toString(response.getEntity(), "UTF-8");
				EntityUtils.consume(entity);
			} finally {
				response.close();
			}
		} finally {
			httpclient.close();
		}
		return ret;
	}

	/**
	 * @Description: 获得KeyStore
	 * @param keyStorePath
	 * @param password
	 * @param type
	 * @return
	 * @throws Exception
	 * @date 2017年11月23日
	 * @author tongxs
	 */
	private static KeyStore getKeyStore(String keyStorePath, String password, String type) throws Exception {
		try(InputStream clientIns = HttpsUtil.class.getResourceAsStream(keyStorePath)){
			KeyStore keyStore = KeyStore.getInstance(type);
			keyStore.load(clientIns, password.toCharArray());
			return keyStore;
		}
		
	}

	/**
	 * @Description: 覆写HostnameVerifier，消除冗余代码
	 * @date 2017年11月23日
	 * @author tongxs
	 */
	public static class MyHostnameVerifier implements HostnameVerifier {

		@Override
		public boolean verify(String hostname, SSLSession session) {
			return true;
		}
	}

}
